
package edu.predatorwars.client;

import java.awt.Point;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.UUID;

import edu.predatorwars.client.visualization.DataSet;
import edu.predatorwars.shared.models.Board;
import edu.predatorwars.shared.models.Creature;
import edu.predatorwars.shared.models.Location;
import edu.predatorwars.shared.models.Move;
import edu.predatorwars.shared.models.Player;
import edu.predatorwars.shared.models.PlayerStatus;
import edu.predatorwars.shared.models.Terrain;
import edu.usm.predatorwars.ClientMask;

public class Client extends ClientBase {
	
	
	
	
	public Client(ClientMask mask) {
		super(mask);
		enterWaitForWorkLoop();
	}
	
	
	public void refreshGameList() {
		visualizationStarter.setGames(clientmask.refreshGameList());
		if (refresh_games)
		this.clientWork.offer(new Runnable() {
			public void run() {
				refreshGameList();
				try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();				}
			}
		});
		System.out.println("refresh");
	}
	
	//TODO: this method could be used to define computer controlled behavior
	@Override
	protected void doBehavior() {
		// TODO Auto-generated method stub
			
	}
	
	
	public static void main(String[] args)
	{
		
		try {
			
			//change if/when servers are setup
			ServerSocket lm = new ServerSocket(0); //gets a free port
			String free_port = Integer.toString(lm.getLocalPort());
			lm.close();
			new Client(buildClientMask(free_port, "http://localhost:8080"));

			
		} catch (UnknownHostException e) {
			System.out.println("Unable to build client mask...returning");
			return;
		}
		catch (IOException e2) {
			System.out.println("Unable to build client mask...returning");
			return;
		}
		
	}
	
	
	/*visualization callbacks */

	//Join Button pressed by user
	//Force visualization to show waiting message
	//clientmask joins selected game
	public void joinGame(UUID gameID) {
		visualizationStarter.showWaiting();
		clientmask.joinGame(gameID, this);
	}
	
	
	//Create Button pressed by user
	//Force visualization to show waiting message
	//clientmask creates game
	//TODO:add mapname/gamename and maximum player functionality functionality
	public void createGame(String mapName, int maxPlayers) {
		visualizationStarter.showWaiting();
		clientmask.createGame(this);
		
	}

	//this method is not run on client thread, it has to be run on a separate thread (currently is being run on the visualization thread)
	//needed to block the creatureResponse before it returned (see onSelectCreature)
	//This method wakes up the client and allows clientmask to finish response
	public void selectedCreature(DataSet<Creature, Float[]> creature) {
		Float[] color = creature.getValue();
		clientmask.getPlayer().setColor(color[0], color[1], color[2]);

		visualizationStarter.showWaiting();
		synchronized (responseLock) {
			responseCreature = creature.getKey();
			responseLock.notify();
		}
	}

	
	private boolean observerMode = false;
	@Override
	public void observeGame(UUID gameID) {
		observerMode = true;
		visualizationStarter.showWaiting();
		clientmask.getPlayer().setPlayerStatus(PlayerStatus.OBSERVER);
		clientmask.joinGame(gameID, this);
	}
	
	
	public void exitGame() {
		//handle clientmask stuff
		visualizationStarter.createAndShowSelectionScreen();
	}

	public void moved(Point location) {
		synchronized(responseLock) {
			move = new Move(location.x, location.y);
			responseLock.notifyAll();
		}
	}

	public void endedTurn() {
		synchronized(responseLock) {
			move = null;
			responseLock.notifyAll();
		}
	}

	public void confirmedModalDialog() {
		visualizationStarter.showLose(false);
	}

	//Visualization notifies the client that the game ListBox is visible.
	//Client begins periodically refreshing and notifying Visualization of changes
	public void gameListVisible(boolean b) {
		refresh_games = b;
		if (b) this.refreshGameList();
	}
	

	
	@Override
	public void selectionScreenCreated() {
		observerMode = false;
		refreshGameList();
	}

	@Override
	public void boardScreenCreated() {
		visualizationStarter.setMyPlayer(clientmask.getPlayer());
	}
	
	
	
	
	/*client mask events*/
	Board currentBoard;
	@Override
	public void onBoardUpdate(Board board, List<Player> playerList, int myX,
			int myY) {
		currentBoard = board;
		visualizationStarter.setBoard(board.getLocations());
		
	}


	@Override
	public void onGameLoadingState(List<Player> players) {
		// TODO Auto-generated method stub
		
	}


	@Override
	public void onGameStartState(List<Player> players) {
		visualizationStarter.createAndShowBoardScreen();
		
	}


	@Override
	public void onGameEndState(List<Player> players) {
		
		//find the current player and get their status
		Player myPlayerNotUpdated = clientmask.getPlayer();
		PlayerStatus myStatus = myPlayerNotUpdated.getPlayerStatus();
		for (int i=0;i<players.size();i++)
			if (myPlayerNotUpdated.equals(players.get(i))) 
				if (myStatus != PlayerStatus.OBSERVER)	myStatus = players.get(i).getPlayerStatus();
		
		System.out.println(myStatus);
		
		if (myStatus == PlayerStatus.ALIVE)
			visualizationStarter.showWin(true);
		else if (myStatus == PlayerStatus.DEAD)
			visualizationStarter.showLose(true);
		else if (myStatus == PlayerStatus.OBSERVER)
		{}
	}

	
	//some fuzzy logic for turns left
	int moves_so_far = 0;
	Move move;
	@Override
	public Move onMove(Set<Move> availableMovements, int myX, int myY) {
		
		if (moves_so_far == 0) visualizationStarter.setTurnsLeft((int)clientmask.getPlayer().getCreature().getStat(Creature.STAT_SPEED));
		
		visualizationStarter.setMoves(
				Arrays.asList(availableMovements.toArray(new Move[0])));
		Move copy = null;
		synchronized(responseLock) {
			while (move == null) {
				try {
					responseLock.wait();
					break;
				} catch (InterruptedException e) {}
			}
			copy = move;
			move = null;
		}
		//check if user clicked end turn button
		int moves_left = 0;
		if (copy == null) {
			copy = new Move(myX, myY);
		}
		
		//check if there is a player on the chosen location
		if ( currentBoard.getLocation(copy.getTargetPoint()).getPlayer() != null ) {
			moves_so_far = 0;
		}
		else {
		
			moves_left = (int) clientmask.getPlayer().getCreature().getStat(Creature.STAT_SPEED) - ++moves_so_far;
		}
		
		visualizationStarter.setMoves(new ArrayList<Move>());
		
		
		if (moves_left == 0) moves_so_far = 0;
		visualizationStarter.setTurnsLeft(moves_left);
		
		return copy;
	}

	
	Creature responseCreature;
	@Override
	public Creature onSelectCreature(List<Creature> creatures) {
		responseCreature = null;
		if (this.observerMode) return creatures.get(0);
		
		visualizationStarter.setCreatures(creatures);
		visualizationStarter.showCreatures();
		
		
		//block the client from responding until a player is a selected
		synchronized(responseLock) {
			
			while (responseCreature == null) {
			try {responseLock.wait();} catch (InterruptedException e) {
				e.printStackTrace();
			}
			}
		}
		
		return responseCreature;
	}


	
	
}